/* eslint-disable react/no-access-state-in-setstate */
/**
 * md评论框
 * @param {object} commitInfo 接口返回的commit对象
 * @param {boolean} condensed 使用浓缩版，不带Notice组件，间距更小，在compare、cr等commit列表中使用
 */

import React from 'react';
import PropTypes from 'prop-types';
import { Button, Message, Balloon } from '@teamix/ui';
import MarkdownIt from 'markdown-it';
import hljs from 'utils/hl.js';
import { YunxiaoIcon } from '@alife/devops-ui';
import upload from './upload';
import './index.scss';
import KEYCODE from 'utils/keycode';
import { ENUM } from 'utils/constants';
import { getPathWithRootPath } from 'utils/router';
import milt from 'markdown-it-link-target';
import { filterXSS } from 'xss';
import track from 'utils/track';
import intl from '../../locale';

const { ctrlKey } = ENUM.getOSKeyMap();

const md = new MarkdownIt({
  html: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return hljs.highlight(lang, str).value;
      } catch (__) {
        return '';
      }
    }

    return ''; // 使用额外的默认转义
  },
}).use(milt, {
  target: '_blank',
});

const { pathResource } = window.FORCE;

export default class MdEditor extends React.Component {
  static propTypes = {
    btnAlign: PropTypes.string,
    help: PropTypes.string,
  };

  static defaultProps = {
    btnAlign: 'right',
    // 眼睛旁边的帮助文案
    help: '',
  };

  constructor(props) {
    super(props);
    const { initValue } = this.props;
    this.state = {
      value: initValue || '',
      extraValue: {}, // 配合 extraOptionsArea 属性使用，extraOptionsArea 里的组件可以修改 extraValue，最终传给 onSubmit
      isPreview: false,
    };
  }

  UNSAFE_componentWillReceiveProps(nextProps) {
    if (this.props.initValue !== nextProps.initValue) {
      this.setState({
        value: nextProps.initValue || '',
      });
    }
  }

  componentDidMount() {
    const { value } = this.state;
    const { noAutoFocus } = this.props;

    if (!noAutoFocus) {
      this.textarea.focus();
    }
    this.textarea.setSelectionRange(value.length, value.length);
    this.mdRef.addEventListener('keydown', this.handleKeyEvents);
  }

  handleKeyEvents = (e) => {
    e.stopPropagation();
    const { value } = this.state;
    if (!value) {
      return;
    }
    // ctrl + enter 更新草稿
    if (e[ctrlKey] && e.shiftKey && e.keyCode === KEYCODE.ENTER) {
      if (!this.props.onSubmitImmediate) {
        return;
      }
      this.props.onSubmitImmediate(value, false);
      this.setState({
        value: '',
        extraValue: null,
      });

      track({
        action: 'submit_the_comment',
        page: '',
        type: 'shortcuts',
        control: '',
      });

      return;
    }

    if (e[ctrlKey] && e.keyCode === KEYCODE.ENTER) {
      if (!this.props.onSubmit) {
        return;
      }
      this.props.onSubmit(value, true);
      this.setState({
        value: '',
        extraValue: null,
      });

      track({
        action: 'submit_the_draft',
        page: '',
        type: 'shortcuts',
        control: '',
      });
    }
  };

  componentWillUnmount() {
    this.mdRef.removeEventListener('keydown', this.handleKeyEvents);
  }

  onChange = (event) => {
    this.setState(
      {
        value: event.target.value,
      },

      () => {
        this.props.onChangevalue && this.props.onChangevalue(this.state.value);
      },
    );
  };

  // 粘贴上传图片逻辑
  onPaste = (event) => {
    const { clipboardData } = event;
    if (clipboardData.items.length <= 0) {
      return;
    }

    let file;
    [...clipboardData.items].forEach((item) => {
      if (item.kind === 'file') {
        file = item.getAsFile();
      }
    });

    if (!file) {
      return;
    }

    upload({
      action: getPathWithRootPath(`/api/v3/common/image?type=comment&project_id=${pathResource.id}${
        window.FORCE.csrfTokenName ? `&${window.FORCE.csrfTokenName}=${window.FORCE.csrfToken}` : ''
      }`),
      filename: 'file',
      file,
      bin: file,
      multipart: false,
      onProgress: () => {},
      onSuccess: (ret) => {
        this.setState(
          {
            value: `${this.state.value}${this.state.value ? '\n' : ''}![](${ret.imgUrl})`,
          },

          () => {
            this.props.onChangevalue && this.props.onChangevalue(this.state.value);
          },
        );
      },
      onError: (err, xhr) => {
        const msg = xhr && xhr.message;
        Message.error(
          msg ||
            intl.get({
              id: 'code-assets.components.mdEditor.UploadFailed',
              defaultMessage: '上传失败',
            }),
        );
      },
      onAbort: () => {
        Message.error(
          intl.get({
            id: 'code-assets.components.mdEditor.UploadFailed',
            defaultMessage: '上传失败',
          }),
        );
      },
    });

    event.preventDefault();
  };

  render() {
    const {
      onSubmit,
      onCancel,
      onSubmitImmediate,
      placeholder,
      submitBtnText,
      size,
      renderExtraOptionsArea,
      useInLog,
      textareaStyle = {},
      btnAlign,
      help,
    } = this.props;
    const { value, extraValue, isPreview } = this.state;

    const cancelEle = onCancel ? (
      <Button
        type="primary"
        text
        // size={size || 'medium'}
        className="md-editor-btn"
        onClick={() => {
          onCancel(value);
        }}
      >
        {intl.get({ id: 'code-assets.components.mdEditor.Cancel', defaultMessage: '取消' })}
      </Button>
    ) : null;

    const submitImmediateEle = onSubmitImmediate ? (
      <Button
        className="md-editor-btn"
        type={onSubmit ? 'normal' : 'primary'}
        // size={size || 'medium'}
        disabled={!value}
        onClick={() => {
          if (!value) {
            return;
          }
          onSubmitImmediate(value, false);
          this.setState({
            value: '',
            extraValue: null,
          });
        }}
      >
        发布
      </Button>
    ) : null;

    const submitEle = onSubmit ? (
      <Button
        className="md-editor-btn"
        type="primary"
        // size={size || 'medium'}
        disabled={!value}
        onClick={() => {
          if (!value) {
            return;
          }
          onSubmit(value, true);
          this.setState({
            value: '',
            extraValue: null,
          });
        }}
      >
        {submitBtnText ||
          intl.get({ id: 'code-assets.components.mdEditor.Submitted', defaultMessage: '提交' })}
      </Button>
    ) : null;

    let btnArr = [];
    if (btnAlign === 'right') {
      btnArr = [cancelEle, submitImmediateEle, submitEle];
    } else {
      btnArr = [submitImmediateEle, submitEle, cancelEle];
    }

    return (
      <div
        className={`md-editor clearfix ${size === 'small' ? 'md-editor-small' : ''}`}
        ref={(ref) => {
          this.mdRef = ref;
        }}
      >
        <div className="md-editor-panel">
          <div style={{ display: isPreview ? 'none' : 'block' }}>
            <textarea
              className="md-editor-panel-textarea"
              style={textareaStyle}
              onChange={this.onChange}
              onPaste={this.onPaste}
              value={value}
              ref={(textarea) => {
                this.textarea = textarea;
              }}
              maxLength={3400}
              placeholder={
                placeholder ||
                intl.get({
                  id: 'code-assets.components.mdEditor.EnterAComment',
                  defaultMessage: '请输入评论',
                })
              }
            />
          </div>
          <div
            style={{ display: isPreview ? 'block' : 'none' }}
            dangerouslySetInnerHTML={{
              __html: filterXSS(md.render(value || ''), {
                onIgnoreTagAttr: (_, name, val) => {
                  return `${name}=${val}`;
                },
              }),
            }}
            className="md-editor-panel-preview markdown-body"
          />

          <div
            className="md-editor-panel-textarea-tips new"
            style={{ display: useInLog ? 'none' : 'flex' }}
          >
            {help ? <div>{help}</div> : null}
            <Balloon.Tooltip
              trigger={
                <Button
                  type="normal"
                  text
                  style={{
                    minWidth: 'auto',
                    margin: '0 12px',
                  }}
                  onClick={() => {
                    this.setState({
                      isPreview: !isPreview,
                    });
                  }}
                >
                  <YunxiaoIcon type={!isPreview ? 'visible-line' : 'invisible-line'} />
                </Button>
              }
              align="t"
            >
              {isPreview
                ? intl.get({
                    id: 'code-assets.components.mdEditor.ClosePreview',
                    defaultMessage: '关闭预览',
                  })
                : intl.get({
                    id: 'code-assets.components.mdEditor.EnablePreview',
                    defaultMessage: '开启预览',
                  })}
            </Balloon.Tooltip>
          </div>
        </div>
        <div className={`comment-btn ${btnAlign === 'left' ? 'flex-start' : ''}`}>{btnArr}</div>

        {renderExtraOptionsArea ? (
          <div className="extra-options-area">
            {renderExtraOptionsArea({
              updateExtraValue: (val) => {
                this.setState({
                  extraValue: val,
                });
              },
              extraValue,
            })}
          </div>
        ) : null}
      </div>
    );
  }
}
